package com.campuscarbooking.api.service.impl;

import com.campuscarbooking.api.annotation.LogExecutionTime;
import com.campuscarbooking.api.annotation.LogMethod;
import com.campuscarbooking.api.dto.BusScheduleDTO;
import com.campuscarbooking.api.dto.DriverDTO;
import com.campuscarbooking.api.dto.PageResponse;
import com.campuscarbooking.api.exception.BusinessException;
import com.campuscarbooking.api.model.BusSchedule;
import com.campuscarbooking.api.repository.BusScheduleRepository;
import com.campuscarbooking.api.service.BusScheduleService;
import com.campuscarbooking.api.service.SeatCacheService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class BusScheduleServiceImpl implements BusScheduleService {

    private final BusScheduleRepository busScheduleRepository;
    private final SeatCacheService seatCacheService;

    @Override
    @LogMethod("获取班车列表")
    @LogExecutionTime
    public PageResponse<BusScheduleDTO> getSchedules(
            BusSchedule.RouteDirection routeDirection,
            Boolean isFixed,
            int page,
            int pageSize) {

        Page<BusSchedule> schedulesPage = busScheduleRepository.findByRouteDirectionAndIsFixedAndStatus(
                routeDirection,
                isFixed,
                BusSchedule.Status.active,
                PageRequest.of(page, pageSize)
        );

        List<BusScheduleDTO> schedules = schedulesPage.getContent().stream()
                .map(schedule -> {
                    // 从缓存中获取已预约座位数量，如果缓存不存在则从数据库查询
                    int reservedSeats = seatCacheService.getReservedSeatsCount(schedule.getId());
                    if (reservedSeats == 0) {
                        Integer dbReservedSeats = busScheduleRepository.countReservationsByScheduleId(schedule.getId());
                        if (dbReservedSeats != null && dbReservedSeats > 0) {
                            // 如果数据库中有预约记录但缓存中没有，说明缓存可能过期，需要重新初始化
                            seatCacheService.initializeSeats(schedule);
                            reservedSeats = dbReservedSeats;
                        }
                    }
                    return BusScheduleDTO.fromEntity(schedule, reservedSeats);
                })
                .collect(Collectors.toList());

        return PageResponse.from(schedulesPage, schedules);
    }

    @Override
    @LogMethod("获取班车详情")
    @LogExecutionTime
    public BusScheduleDTO getScheduleById(Long id) {
        BusSchedule schedule = busScheduleRepository.findById(id)
                .orElseThrow(() -> new BusinessException("班车不存在"));

        // 从缓存中获取已预约座位数量，如果缓存不存在则从数据库查询
        int reservedSeats = seatCacheService.getReservedSeatsCount(schedule.getId());
        if (reservedSeats == 0) {
            Integer dbReservedSeats = busScheduleRepository.countReservationsByScheduleId(id);
            if (dbReservedSeats != null && dbReservedSeats > 0) {
                // 如果数据库中有预约记录但缓存中没有，说明缓存可能过期，需要重新初始化
                seatCacheService.initializeSeats(schedule);
                reservedSeats = dbReservedSeats;
            }
        }

        // 实际项目中，这里需要查询司机信息
        DriverDTO driver = null;

        return BusScheduleDTO.fromEntity(schedule, reservedSeats, driver);
    }

    @Override
    @Transactional
    @LogMethod("创建班车")
    @LogExecutionTime
    public BusScheduleDTO createSchedule(BusScheduleDTO busScheduleDTO) {
        BusSchedule schedule = new BusSchedule();
        schedule.setRouteDirection(BusSchedule.RouteDirection.valueOf(busScheduleDTO.getRouteDirection()));
        schedule.setDepartureTime(LocalTime.parse(busScheduleDTO.getDepartureTime()));
        schedule.setArrivalTime(LocalTime.parse(busScheduleDTO.getArrivalTime()));
        schedule.setPrice(busScheduleDTO.getPrice());
        schedule.setCapacity(busScheduleDTO.getCapacity());
        schedule.setIsFixed(busScheduleDTO.getIsFixed());
        schedule.setStatus(BusSchedule.Status.active);

        BusSchedule savedSchedule = busScheduleRepository.save(schedule);
        
        // 初始化座位缓存
        seatCacheService.initializeSeats(savedSchedule);
        
        return BusScheduleDTO.fromEntity(savedSchedule);
    }

    @Override
    @Transactional
    @LogMethod("更新班车")
    @LogExecutionTime
    public BusScheduleDTO updateSchedule(Long id, BusScheduleDTO busScheduleDTO) {
        BusSchedule schedule = busScheduleRepository.findById(id)
                .orElseThrow(() -> new BusinessException("班车不存在"));

        if (busScheduleDTO.getRouteDirection() != null) {
            schedule.setRouteDirection(BusSchedule.RouteDirection.valueOf(busScheduleDTO.getRouteDirection()));
        }

        if (busScheduleDTO.getDepartureTime() != null) {
            schedule.setDepartureTime(LocalTime.parse(busScheduleDTO.getDepartureTime()));
        }

        if (busScheduleDTO.getArrivalTime() != null) {
            schedule.setArrivalTime(LocalTime.parse(busScheduleDTO.getArrivalTime()));
        }

        if (busScheduleDTO.getPrice() != null) {
            schedule.setPrice(busScheduleDTO.getPrice());
        }

        boolean capacityChanged = false;
        if (busScheduleDTO.getCapacity() != null && !busScheduleDTO.getCapacity().equals(schedule.getCapacity())) {
            capacityChanged = true;
            schedule.setCapacity(busScheduleDTO.getCapacity());
        }

        if (busScheduleDTO.getIsFixed() != null) {
            schedule.setIsFixed(busScheduleDTO.getIsFixed());
        }

        if (busScheduleDTO.getStatus() != null) {
            schedule.setStatus(BusSchedule.Status.valueOf(busScheduleDTO.getStatus()));
        }

        BusSchedule updatedSchedule = busScheduleRepository.save(schedule);
        
        // 如果座位容量变更，重新初始化座位缓存
        if (capacityChanged) {
            seatCacheService.initializeSeats(updatedSchedule);
        }
        
        return BusScheduleDTO.fromEntity(updatedSchedule);
    }

    @Override
    @Transactional
    @LogMethod("删除班车")
    @LogExecutionTime
    public void deleteSchedule(Long id) {
        BusSchedule schedule = busScheduleRepository.findById(id)
                .orElseThrow(() -> new BusinessException("班车不存在"));

        schedule.setStatus(BusSchedule.Status.inactive);
        busScheduleRepository.save(schedule);
    }
} 